package com.gupao.javavip.rpc.framework.server;

import com.gupao.javavip.rpc.framework.protocol.RPCServiceProvider;
import lombok.extern.apachecommons.CommonsLog;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Component
@CommonsLog
public class RPCServer implements ApplicationContextAware, InitializingBean {
    @Autowired
    private RPCServerConfig config;

    @Autowired
    private RequestHandler handler;

    ExecutorService requestProcessor = Executors.newCachedThreadPool();

    @Override
    public void afterPropertiesSet() throws Exception {
        if (config == null || handler == null) {
            throw new RuntimeException("RPCServer初始化失败……");
        }

        ServerSocket serverSocket = null;
        try {
            serverSocket = new ServerSocket(config.getPort());
            while (true) {
                Socket socket = serverSocket.accept();//BIO
                requestProcessor.execute(new RPCRequestProcessor(socket, handler));
            }
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        } finally {
            if (serverSocket != null) {
                try {
                    serverSocket.close();
                } catch (IOException e) {
                    log.error(e.getMessage(), e);
                }
            }
        }
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        buildServiceMapping(applicationContext);

        registry();
    }

    private void buildServiceMapping(ApplicationContext applicationContext) {
        Map<String, Object> serviceBeanMap = applicationContext.getBeansWithAnnotation(RPCServiceProvider.class);
        if (!serviceBeanMap.isEmpty()) {
            for (Object serviceProvider : serviceBeanMap.values()) {
                try {
                    RequestHandlerHelper.buildServiceMapping(serviceProvider);
                } catch (NoSuchMethodException e) {
                    log.error(e.getMessage(), e);
                } catch (ClassNotFoundException e) {
                    log.error(e.getMessage(), e);
                }
            }
        }
    }

    private void registry() {
        if (StringUtils.isEmpty(config.getServiceId()) || StringUtils.isEmpty(config.getRegistryAdd())) {
            return;
        }

        ZKRegistry zkRegistry = new ZKRegistry(config.getRegistryAdd());
        zkRegistry.registry(config.getServiceId(), buildServiceAdd(config));
    }

    private static String buildServiceAdd(RPCServerConfig config) {
        InetAddress inetAddress = null;
        try {
            inetAddress = InetAddress.getLocalHost();
        } catch (UnknownHostException e) {
            log.error(e.getMessage(), e);
        }
        return inetAddress.getHostAddress() + ":" + config.getPort();// 获得本机的ip地址
    }
}
